package edu.ntu.cloudroid.server.backendservice;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

import edu.ntu.cloudroid.model.PMF;
import edu.ntu.cloudroid.model.data.AbstractData;
import edu.ntu.cloudroid.model.profile.ProfileData;
import edu.ntu.cloudroid.nongui.util.TimeCounter;
import edu.ntu.cloudroid.server.RequestServlet;
import edu.ntu.cloudroid.server.UploadServlet;
import edu.ntu.cloudroid.server.backendservice.util.CloudDroidCache;

/**
 * @author ttadinh For storing and retrieving Person object
 * 
 *         We have extracted the PrivacyPreference and AbstractData to be stored
 *         in different tables.
 */
public class ProfileService {
	private static CloudDroidCache<Key, ProfileData> cache = new CloudDroidCache<Key, ProfileData>(CloudDroidCache.SIZE);

	public static int dataType; //latest data type
	static TimeCounter counter = new TimeCounter("profile insert", UploadServlet.logger);
	static Object lock = new Object();
	
	public static void purgeCache(){
		 cache = new CloudDroidCache<Key, ProfileData>(CloudDroidCache.SIZE);
	}
	public static void addProfile(ProfileData p) throws Exception {
		dataType = p.getDataId();	
		counter.start(true);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.currentTransaction().begin();
			p.setKey(getProfileKey(p.getEmailAddress()));
			pm.makePersistent(p);
			pm.currentTransaction().commit();
		} finally {
			if (pm.currentTransaction().isActive()) {
				pm.currentTransaction().rollback();
			}
			pm.close();
		}
		//FriendService.initializeFriendList(p);
		counter.end(true);		
	}

	public static ProfileData getProfile(Key k) throws Exception {
		
		ProfileData p = cache.get(k);
		if (null == p) { 
			PersistenceManager pm = PMF.get().getPersistenceManager();
			pm.getFetchPlan().addGroup(ProfileData.FETCH_GROUP_NAME);
			pm.getFetchPlan().setMaxFetchDepth(2);

			p = pm.getObjectById(ProfileData.class, k);
			p = pm.detachCopy(p);
			cache.put(k, p);
			pm.close();
		}
		
		return p;
		
	}

	public static ProfileData getProfile(String emailAddress) throws Exception {

		Key k = getProfileKey(emailAddress);
		ProfileData p = cache.get(k);
		if (null == p) {

			PersistenceManager pm = PMF.get().getPersistenceManager();
			pm.getFetchPlan().addGroup(ProfileData.FETCH_GROUP_NAME);
			pm.getFetchPlan().setMaxFetchDepth(2);

			p = pm.getObjectById(ProfileData.class, k);
			p = pm.detachCopy(p);
			cache.put(k, p);
			pm.close();
		}
		
		return p;
		}
	
	
	public static void deleteAllProfiles() throws Exception{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		/*pm.getFetchPlan().addGroup(AbstractData.FETCH_GROUP_NAME);
		pm.getFetchPlan().setMaxFetchDepth(2);*/	
		List<AbstractData> returnList = new ArrayList<AbstractData>();
		long start = System.currentTimeMillis();
		try {
			Query query = pm.newQuery(ProfileData.class);
			
			//query.setFilter("profileKey == personParam && timestamp > timestampParam");
			
			//query.declareParameters(Key.class.getName() + " personParam, " + Date.class.getName() + " timestampParam");
			//query.setOrdering("timestamp asc");
			
			@SuppressWarnings("unchecked")
			List<ProfileData> result = (List<ProfileData>) query.execute();
			
			for (ProfileData v : result){
				pm.deletePersistent(v);
			}			
			//query.execute();
			
			long end = System.currentTimeMillis();
			RequestServlet.logger.info("profile delete time = "+(end-start));
		} finally {
			pm.close();		
		}
	}

	public static void deleteProfile(String emailAddress) throws Exception {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		long start = System.currentTimeMillis();
		try {
			ProfileData p = pm.getObjectById(ProfileData.class,
					getProfileKey(emailAddress));
			Key k = p.getKey();			
			pm.deletePersistent(p);
			cache.delete(k);
			System.out.println("Deleted old profile "+emailAddress);
		} catch (Exception e) {
			System.err
			.println("Profile is not current on the store, creating new one");			
		} finally {
			pm.close();
		}
		long end = System.currentTimeMillis();
		UploadServlet.logger.info("profile delete time = "+(end-start));
	}

	public static Key getProfileKey(String emailAddress) {
		return KeyFactory.createKey(ProfileData.class.getSimpleName(),
				emailAddress);
	}
}
